package api

import (
	"context"
	"errors"
	"fmt"
	"net/url"
	"strings"

	"zhonghui/console/models"
	"zhonghui/console/service"
	"zhonghui/console/structs"
	"zhonghui/console/warehouse/helperx"
	"zhonghui/console/warehouse/logx"
	"zhonghui/console/warehouse/respx"
	"zhonghui/console/wxutil"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
)

type CreateConfigRequest struct {
	Describe string `json:"describe" binding:"required" validate:"max=64"`
	CorpId   string `json:"corp_id" binding:"required" validate:"max=64"`
	Category int32  `json:"category" binding:"required" validate:"oneof=1 2"`
	Scene    int32  `json:"scene" binding:"required" validate:"oneof=1 2"`
	Channel  string `json:"channel" binding:"required" validate:"max=64"`
	//Users    []string `json:"users" binding:"required" validate:"required"`
}

func (server *Server) CreateConfig(c *gin.Context) {
	var req CreateConfigRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		respx.Error(c, "params err", err)
		return
	}
	if err := validator.New().Struct(req); err != nil {
		respx.Error(c, "params validation err", err)
		return
	}

	if err := service.CreateContact(server.store, req.Describe, req.CorpId, req.Category, req.Scene, req.Channel, []string{}); err != nil {
		respx.Error(c, "create contact err", err)
		return
	}
	respx.Success(c, "ok", nil)
}

type getEmployeeListByConfigIdRequest struct {
	Id int64 `uri:"id"  binding:"required"`
}

type getEmployeeListByConfigIdQueryRequest struct {
	CorpId string `form:"corp_id"  binding:"required"`
}

func (server *Server) getEmployeeListByConfigId(c *gin.Context) {
	var req getEmployeeListByConfigIdRequest
	if err := c.ShouldBindUri(&req); err != nil {
		respx.Error(c, "params err", err)
		return
	}
	var reqQuery getEmployeeListByConfigIdQueryRequest
	if err := c.ShouldBindQuery(&reqQuery); err != nil {
		respx.Error(c, "params query err", err)
		return
	}
	if err := validator.New().Struct(req); err != nil {
		respx.Error(c, "params validation err", err)
		return
	}

	cache := wxutil.NewCache()

	list, err := server.store.GetContactEmployeeById(context.Background(), req.Id)
	if err != nil {
		respx.Error(c, "get employee list err", err)
		return
	}

	for k := range list {
		list[k].Status = cache.Client().Get(context.Background(), fmt.Sprintf(structs.ActiveExpireKey, reqQuery.CorpId, list[k].OpenUserID)).Val()
	}

	respx.Success(c, list, nil)
}

//
type UpdateEmployeeRequest struct {
	ContactID      int64    `json:"contact_id" binding:"required" validate:"gt=0"`
	CorpID         string   `json:"corp_id" binding:"required" validate:"max=64"`
	EmployeeSelect []string `json:"employee_select" binding:"required" validate:"required"`
	WelcomeMessage string   `json:"welcome_message" binding:"required" validate:"max=2048"`
}

func (server *Server) update_employee(c *gin.Context) {

	var req UpdateEmployeeRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		respx.Error(c, "params err", err)
		return
	}

	if err := validator.New().Struct(req); err != nil {
		respx.Error(c, "params validation err", err)
		return
	}

	users := make([]service.Users, 0)
	for _, v := range req.EmployeeSelect {
		temps := strings.Split(v, ":")
		if len(temps) > 2 {
			users = append(users, service.Users{
				UserId:     temps[2],
				Name:       temps[1],
				OpenUserId: temps[0],
			})
		}
	}

	km, _ := url.PathUnescape(req.WelcomeMessage)
	err := service.CreateEmployee(server.store, req.ContactID, req.CorpID, users, km)
	if err != nil {
		logx.Zap().Error("update employee err", "err", err)
		respx.Error(c, "update employee err", err)
		return
	}

	// 异步更新人员信息
	go func() {

	}()

	respx.Success(c, "ok", nil)
}

type UpdateConfigRequest struct {
	Id       int64  `json:"id" binding:"required" validate:"gt=0"`
	ConfigId string `json:"config_id" binding:"required" validate:"max=64"`
	CorpId   string `json:"corpid" binding:"required" validate:"max=64"`
}

func (server *Server) UpdateConfig(c *gin.Context) {

	var req UpdateConfigRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		respx.Error(c, "params err", err)
		return
	}

	accessToken, err := server.store.GetAccessTokenByCorpId(context.Background(), req.CorpId)
	if err != nil {
		logx.Zap().Error("PushConfig GetAccessTokenByCorpId", "err", err, "id", req.Id)
		respx.Error(c, "get access token err", err)
		return
	}

	if err := validator.New().Struct(req); err != nil {
		respx.Error(c, "params validation err", err)
		return
	}

	_, users, err := service.GetPushContactConfig(server.store, req.Id)
	if err != nil {
		logx.Zap().Error("PushConfig GetPushContactConfig", "err", err, "id", req.Id)
		respx.Error(c, "get contact err", err)
		return
	}

	resp, err := service.UpdateContactConfig(accessToken, service.UpdateContactConfigRequest{
		ConfigId: req.ConfigId,
		User:     users,
	})

	if err != nil {
		logx.Zap().Error("UpdateConfig UpdateContactConfig", "err", err, "id", req.Id)
		respx.Error(c, "update contact err", err)
		return
	}

	if resp.Errcode != 0 {
		logx.Zap().Error("UpdateConfig UpdateContactConfig", "err", errors.New(resp.Errmsg), "id", req.Id)
		respx.Error(c, resp.Errmsg, errors.New(resp.Errmsg))
		return
	}

	logx.Zap().Infow("UpdateConfig CreateContactConfig", "accessToken", accessToken, "resp", resp)

	if err := server.store.UpdateContactTime(context.Background(), models.UpdateContactTimeParams{
		ID: req.Id,
	}); err != nil {
		logx.Zap().Error("UpdateConfig UpdateContactTime", "err", err, "id", req.Id)
		respx.Error(c, "update contact err", err)
		return
	}

	respx.Success(c, "pong", nil)
}

type GetConfigListRequest struct {
	structs.PageBase
	CorpId   string `form:"corpid" binding:"required" validate:"max=64"`
	ConfigId string `form:"config_id" validate:"max=64"`
}

type GetConfigListResponse struct {
	models.SysContact
	Users []string `json:"users"`
}

func (server *Server) GetConfigList(c *gin.Context) {

	req := GetConfigListRequest{}
	if err := c.ShouldBindQuery(&req); err != nil {
		logx.Zap().Errorw("GetConfigList ShouldBindQuery", "err", err)
		respx.Error(c, "parameter error", err)
		return
	}

	if req.ConfigId != "" {
		contact, err := server.store.GetContactByCorpID(context.Background(), models.GetContactByCorpIDParams{
			Corpid:   req.CorpId,
			ConfigID: req.ConfigId,
			Status:   "config",
			Status_2: "deployed",
		})
		if err != nil {
			logx.Zap().Errorw("GetConfigList GetContactByCorpID", "err", err)
			respx.Error(c, "get contact err", err)
			return
		}
		t := int64(0)
		if contact.ID != 0 {
			t = 1
		}
		respx.Success(c, []models.SysContact{contact}, helperx.MakeNormalPagerResp(t, int(req.PageSize)))
		return
	}

	total, err := server.store.GetContactListByCorpIDCount(context.Background(), models.GetContactListByCorpIDCountParams{
		Corpid:   req.CorpId,
		Status:   "config",
		Status_2: "deployed",
	})
	if err != nil {
		logx.Zap().Errorw("GetConfigList GetContactListByCorpIDCount", "err", err)
		respx.Error(c, "get contact list err", err)
		return
	}

	resp, err := server.store.GetContactListByCorpID(context.Background(), models.GetContactListByCorpIDParams{
		Corpid:   req.CorpId,
		Status:   "config",
		Status_2: "deployed",
		Offset:   req.Offset(),
		Limit:    req.PageSize,
	})

	if err != nil {
		logx.Zap().Errorw("GetConfigList GetContactListByCorpID", "err", err)
		respx.Error(c, "get contact list err", err)
		return
	}

	ret := make([]GetConfigListResponse, 0)
	for _, v := range resp {
		ret = append(ret, GetConfigListResponse{
			SysContact: v,
			Users:      []string{},
		})
	}

	respx.Success(c, ret, helperx.MakeNormalPagerResp(total, int(req.PageSize)))
}

func (server *Server) DeleteConfig(c *gin.Context) {
	respx.Success(c, "pong", nil)
}

type PushConfigRequest struct {
	Id int64 `json:"id" binding:"required" validate:"gt=0"`
	//ConfigId string `json:"config_id" binding:"required" validate:"max=64"`
}

func (server *Server) PushConfig(c *gin.Context) {

	var req PushConfigRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		respx.Error(c, "params err", err)
		return
	}

	if err := validator.New().Struct(req); err != nil {
		respx.Error(c, "params validation err", err)
		return
	}

	row, users, err := service.GetPushContactConfig(server.store, req.Id)
	if err != nil {
		logx.Zap().Error("PushConfig GetPushContactConfig", "err", err, "id", req.Id)
		respx.Error(c, "get contact err", err)
		return
	}

	if len(users) == 0 {
		logx.Zap().Error("PushConfig GetPushContactConfig", "err", errors.New("no user"), "id", req.Id)
		respx.Error(c, "请至少配置一名客服人员!", errors.New("no user"))
		return
	}

	accessToken, err := server.store.GetAccessTokenByCorpId(context.Background(), row.Corpid)
	if err != nil {
		logx.Zap().Error("PushConfig GetAccessTokenByCorpId", "err", err, "id", req.Id)
		respx.Error(c, "get access token err", err)
		return
	}

	resp, err := service.CreateContactConfig(accessToken, service.ContactConfigRequest{
		Type:   row.Category,
		Scene:  row.Scene,
		IsTemp: row.IsTemp,
		State:  row.Channel,
		User:   users,
	})
	if err != nil {
		logx.Zap().Error("PushConfig CreateContactConfig", "err", err, "id", req.Id)
		respx.Error(c, "push contact err", err)
		return
	}

	logx.Zap().Infow("PushConfig CreateContactConfig", "accessToken", accessToken, "resp", resp, "user", users)

	if resp.Errcode != 0 {
		logx.Zap().Error("PushConfig CreateContactConfig", "err", resp.Errmsg, "id", req.Id)
		respx.Error(c, resp.Errmsg, errors.New(resp.Errmsg))
		return
	}

	if err := server.store.UpdateContactStatus(context.Background(), models.UpdateContactStatusParams{
		ID:       req.Id,
		Status:   "deployed",
		ConfigID: resp.ConfigID,
		QrCode:   resp.QrCode,
	}); err != nil {
		logx.Zap().Error("PushConfig UpdateContactStatus", "err", err, "id", req.Id)
		respx.Error(c, "update contact err", err)
		return
	}

	respx.Success(c, "ok", nil)
}
